/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Robert M. Fuhrer (rfuhrer@watson.ibm.com), IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TTypes; /** * A type-safe wrapper for Set<TType> that also adds TType-specific * functionality, e.g. subTypes() and superTypes(). */ public class EnumeratedTypeSet extends TypeSet { static private int sCount= 0; static public int getCount() { return sCount; } static public void resetCount() { sCount= 0; } /** * Set containing the TTypes in this EnumeratedTypeSet. */ Set/*<TType>*/ fMembers= new LinkedHashSet(); /** * Constructs a new EnumeratedTypeSet with the members of Set s in it. * All elements of s must be TTypes. */ public EnumeratedTypeSet(Iterator types, TypeSetEnvironment typeSetEnvironment) { super(typeSetEnvironment); while (types.hasNext()) { fMembers.add(types.next()); } sCount++; } /** * Constructs an empty EnumeratedTypeSet. */ public EnumeratedTypeSet(TypeSetEnvironment typeSetEnvironment) { super(typeSetEnvironment); sCount++; } /** * Constructs a new EnumeratedTypeSet with the given single TType in it. */ public EnumeratedTypeSet(TType t, TypeSetEnvironment typeSetEnvironment) { super(typeSetEnvironment); Assert.isNotNull(t); fMembers.add(t); sCount++; } /** * @return <code>true</code> iff this set represents the universe of TTypes */ public boolean isUniverse() { return false; } public boolean equals(Object o) { if (this == o) return true; if (o instanceof EnumeratedTypeSet) { EnumeratedTypeSet other= (EnumeratedTypeSet) o; return fMembers.equals(other.fMembers); } else if (o instanceof SingletonTypeSet) { SingletonTypeSet other= (SingletonTypeSet) o; return (fMembers.size() == 1) && fMembers.contains(other.anyMember()); } else if (o instanceof TypeSet) { TypeSet other= (TypeSet) o; for(Iterator otherIter= other.iterator(); otherIter.hasNext(); ) { if (!fMembers.contains(otherIter.next())) return false; } for(Iterator myIter= fMembers.iterator(); myIter.hasNext(); ) { if (!other.contains((TType) myIter.next())) return false; } return true; } else return false; } public int hashCode() { return 37 + fMembers.hashCode(); } /** * Computes and returns a <em>new</em> EnumeratedTypeSet representing the intersection of the * receiver with s2. Does not modify the receiver. * @param s2 */ protected TypeSet specialCasesIntersectedWith(TypeSet s2) { if (s2 instanceof EnumeratedTypeSet) { EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); result.addAll(this); // copy first since retainAll() modifies in-place result.retainAll(s2); if (result.size() > 0) return result; else return getTypeSetEnvironment().getEmptyTypeSet(); } return null; } /** * Modifies this EnumeratedTypeSet to represent the intersection of the receiver with s2. * @param s2 */ public void intersectWith(TypeSet s2) { if (isUniverse()) { if (s2.isUniverse()) return; // More than an optimization: the universe never contains array types, so // if s2 has array types, the following will retain them, as it should. EnumeratedTypeSet ets2= (EnumeratedTypeSet) s2; fMembers= new LinkedHashSet(); fMembers.addAll(ets2.fMembers); } else retainAll(s2); } /** * @return a new TypeSet representing the set of all sub-types of the * types in the receiver */ public TypeSet subTypes() { if (isUniverse()) return makeClone(); // subtypes(universe) = universe if (fMembers.contains(getJavaLangObject())) return getTypeSetEnvironment().getUniverseTypeSet(); return getTypeSetEnvironment().createSubTypesSet(this); } public static EnumeratedTypeSet makeArrayTypesForElements(Iterator/*<TType>*/ elemTypes, TypeSetEnvironment typeSetEnvironment) { EnumeratedTypeSet result= new EnumeratedTypeSet(typeSetEnvironment); while (elemTypes.hasNext()) { TType t= (TType) elemTypes.next(); result.add(TTypes.createArrayType(t, 1)); } // result.initComplete(); return result; } /** * @return a new TypeSet representing the set of all super-types of the * types in the receiver */ public TypeSet superTypes() { if (isUniverse()) return makeClone(); // The supertypes of the universe is the universe return getTypeSetEnvironment().createSuperTypesSet(this); } public TypeSet makeClone() { EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); result.fMembers.addAll(fMembers); result.initComplete(); return result; } /* (non-Javadoc) * @see java.util.Set#size() */ public int size() { return fMembers.size(); } /* (non-Javadoc) * @see java.util.Set#clear() */ public void clear() { if (isUniverse()) fMembers= new LinkedHashSet(); else fMembers.clear(); } /* (non-Javadoc) * @see java.util.Set#isEmpty() */ public boolean isEmpty() { return fMembers.isEmpty(); } /* (non-Javadoc) * @see java.util.Set#toArray() */ public TType[] toArray() { return (TType[]) fMembers.toArray(new TType[fMembers.size()]); } /* (non-Javadoc) * @see java.util.Set#add(java.lang.Object) */ public boolean add(TType t) { // Doesn't make sense to do here what other methods do (copy-and-modify) Assert.isTrue(!isUniverse(), "Someone's trying to expand the universe!"); //$NON-NLS-1$ return fMembers.add(t); } /* (non-Javadoc) * @see java.util.Set#contains(java.lang.Object) */ public boolean contains(TType t) { if (isUniverse()) return true; return fMembers.contains(t); } /* (non-Javadoc) * @see java.util.Set#remove(java.lang.Object) */ public boolean remove(TType t) { if (isUniverse()) fMembers= cloneSet(fMembers); return fMembers.remove(t); } private Set cloneSet(Set members) { Set result= new LinkedHashSet(); result.addAll(members); return result; } /* (non-Javadoc) * @see java.util.Set#addAll(java.util.Collection) */ public boolean addAll(TypeSet s) { if (s instanceof EnumeratedTypeSet) { EnumeratedTypeSet ets= (EnumeratedTypeSet) s; return fMembers.addAll(ets.fMembers); } else { EnumeratedTypeSet ets= s.enumerate(); return fMembers.addAll(ets.fMembers); } } public TypeSet addedTo(TypeSet that) { EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); result.addAll(this); result.addAll(that); result.initComplete(); return result; } /* (non-Javadoc) * @see java.util.Set#containsAll(java.util.Collection) */ public boolean containsAll(TypeSet s) { if (isUniverse()) return true; if (s.isUniverse()) return false; EnumeratedTypeSet ets= s.enumerate(); return fMembers.containsAll(ets.fMembers); } /* (non-Javadoc) * @see java.util.Set#removeAll(java.util.Collection) */ public boolean removeAll(EnumeratedTypeSet s) { if (isUniverse()) fMembers= cloneSet(fMembers); return fMembers.removeAll(s.fMembers); } /* (non-Javadoc) * @see java.util.Set#retainAll(java.util.Collection) */ public boolean retainAll(TypeSet s) { if (s.isUniverse()) return false; EnumeratedTypeSet ets= (EnumeratedTypeSet) s; if (isUniverse()) { fMembers= cloneSet(ets.fMembers); return true; } else return fMembers.retainAll(ets.fMembers); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isSingleton() */ public boolean isSingleton() { return fMembers.size() == 1; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#anyMember() */ public TType anyMember() { return (TType) fMembers.iterator().next(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#upperBound() */ public TypeSet upperBound() { if (fMembers.size() == 1) return new SingletonTypeSet((TType) fMembers.iterator().next(), getTypeSetEnvironment()); if (fMembers.contains(getJavaLangObject())) return new SingletonTypeSet(getJavaLangObject(), getTypeSetEnvironment()); EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); // Add to result each element of fMembers that has no proper supertype in fMembers result.fMembers.addAll(fMembers); for(Iterator iter= fMembers.iterator(); iter.hasNext(); ) { TType t= (TType) iter.next(); if (t.isArrayType()) { ArrayType at= (ArrayType) t; int numDims= at.getDimensions(); for(Iterator subIter=TTypes.getAllSubTypesIterator(at.getElementType()); subIter.hasNext(); ) { result.fMembers.remove(TTypes.createArrayType(((TType) subIter.next()), numDims)); } } else { for (Iterator iterator= TTypes.getAllSubTypesIterator(t); iterator.hasNext();) { result.fMembers.remove(iterator.next()); } } } result.initComplete(); return result; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#lowerBound() */ public TypeSet lowerBound() { if (fMembers.size() == 1) return new SingletonTypeSet((TType) fMembers.iterator().next(), getTypeSetEnvironment()); EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); // Add to result each element of fMembers that has no proper subtype in fMembers result.fMembers.addAll(fMembers); for(Iterator iter= fMembers.iterator(); iter.hasNext(); ) { TType t= (TType) iter.next(); // java.lang.Object is only in the lower bound if fMembers consists // of only java.lang.Object, but that case is handled above. if (t.equals(getJavaLangObject())) { result.fMembers.remove(t); continue; } if (t instanceof ArrayType) { ArrayType at= (ArrayType) t; int numDims= at.getDimensions(); for(Iterator superIter=TTypes.getAllSuperTypesIterator(at.getElementType()); superIter.hasNext(); ) { result.fMembers.remove(TTypes.createArrayType(((TType) superIter.next()), numDims)); } } else { for (Iterator iterator= TTypes.getAllSuperTypesIterator(t); iterator.hasNext();) { result.fMembers.remove(iterator.next()); } } } if (result.size() > 0) return result; else return getTypeSetEnvironment().getEmptyTypeSet(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueLowerBound() */ public boolean hasUniqueLowerBound() { return fMembers.size() == 1; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueUpperBound() */ public boolean hasUniqueUpperBound() { return fMembers.size() == 1; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueLowerBound() */ public TType uniqueLowerBound() { if (fMembers.size() == 1) return (TType) fMembers.iterator().next(); return null; } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueUpperBound() */ public TType uniqueUpperBound() { if (fMembers.size() == 1) return (TType) fMembers.iterator().next(); return null; } /* (non-Javadoc) * @see java.util.Set#iterator() */ public Iterator iterator() { return fMembers.iterator(); } /* (non-Javadoc) * @see java.util.Set#toArray(java.lang.Object[]) */ public TType[] toArray(TType[] a) { return (TType[]) fMembers.toArray(a); } /** * Limits the display of set elements to the first sMaxElements. */ private static final int sMaxElements= 10; // Integer.MAX_VALUE; /* * (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { StringBuffer b= new StringBuffer(); b.append("{" + fID+ ":"); //$NON-NLS-1$ //$NON-NLS-2$ if (isUniverse()) b.append(" <universe>"); //$NON-NLS-1$ else { int count=0; Iterator iter; for(iter= iterator(); iter.hasNext() && count < sMaxElements; count++) { TType type= (TType) iter.next(); b.append(' ') .append(type.getPrettySignature()); if (iter.hasNext()) b.append(','); } if (iter.hasNext()) b.append(" ..."); //$NON-NLS-1$ } b.append(" }"); //$NON-NLS-1$ return b.toString(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#enumerate() */ public EnumeratedTypeSet enumerate() { return this; // (EnumeratedTypeSet) makeClone(); } public void initComplete() { Assert.isTrue(! fMembers.isEmpty()); } }